import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Not, Repository } from 'typeorm';
import { SurveyEntity, SurveyType } from './survey.entity';
import { CreateSurveyDto, UpdateSurveyDto } from './survey.dto';
import { isNil, omitBy } from 'lodash';
import { ErrorEnum } from '~/constants/error-code.constant';
import { CommonStatus } from '~/common/entity/common.entity';

@Injectable()
export class SurveyService {
  private readonly logger = new Logger(SurveyService.name);

  constructor(
    @InjectRepository(SurveyEntity)
    private readonly surveyRepository: Repository<SurveyEntity>
  ) {}

  /**
   * 保存问卷数据
   * @param dto 创建问卷数据传输对象，包含租户ID
   * @returns 保存后的问卷实体
   */
  async save(dto: CreateSurveyDto & { tenantId: number }): Promise<SurveyEntity> {
    // 判断是否传了pageId
    if (!dto.pageId) {
      throw new BadRequestException(ErrorEnum.SURVEY_PAGE_ID_REQUIRED);
    }

    // 根据pageId查询数据
    const survey = await this.surveyRepository.findOne({
      where: {
        tenantId: dto.tenantId, // 确保查询时包含租户ID
        type: dto.type, // 确保查询时包含问卷类型
				pageId: dto.pageId
      },
    });
    // 如果不存在则创建
    if (isNil(survey)) {
      // 校验 link type tenantId
      if (!dto.link || !dto.type || !dto.tenantId || !dto.diseaseId) {
        throw new BadRequestException(ErrorEnum.SURVEY_LINK_TYPE_TENANT_ID_REQUIRED);
      }

      // 创建数据
      const cleanedDto = omitBy(dto, isNil);
      cleanedDto.tenantId = dto.tenantId; // 确保设置租户ID
      cleanedDto.status = cleanedDto.status ?? CommonStatus.YES; // 默认状态为YES

      // 创建数据
      return await this.surveyRepository.save(cleanedDto);
    } else {
      // 如果存在则更新
      const cleanedDto = omitBy(dto, isNil);
      delete cleanedDto.tenantId; // 删除 tenantId 属性

      // 更新数据
      await this.surveyRepository.update(survey.id, cleanedDto);
      return await this.surveyRepository.findOneBy({ id: survey.id });
    }
  }

  /**
   * 更新问卷
   * @param id 问卷ID
   * @param dto 更新问卷数据传输对象
   * @returns 更新后的问卷实体
   */
  async update(id: number, dto: UpdateSurveyDto): Promise<SurveyEntity> {
    const survey = await this.surveyRepository.findOneBy({ id });

    if (isNil(survey)) {
      throw new BadRequestException(ErrorEnum.SURVEY_NOT_FOUND);
    }

    survey.name = dto.name;
    survey.desc = dto.desc;
    survey.link = dto.link;

    // 如果有疾病分类ID，则更新
    if (dto.diseaseId) {
      survey.diseaseId = dto.diseaseId;
    }

    return await this.surveyRepository.save(survey);
  }

  /**
   * 根据问卷ID删除问卷
   * @param id - 要删除的问卷的唯一标识符
   * @throws {BadRequestException} 当未找到指定ID的问卷时抛出异常
   * @returns 当问卷成功删除时解析的Promise
   */
  async remove(id: number): Promise<void> {
    const survey = await this.surveyRepository.findOneBy({ id });

    if (isNil(survey)) {
      throw new BadRequestException(ErrorEnum.SURVEY_NOT_FOUND);
    }

    await this.surveyRepository.remove(survey);
  }

  /**
   * 根据页面ID删除问卷
   *
   * 查找与指定页面ID关联的问卷，并将其从数据库中删除。
   * 如果找不到相应的问卷，则抛出BadRequestException异常。
   *
   * @param pageId - 要删除问卷的页面ID
   * @throws {BadRequestException} 当找不到与指定页面ID关联的问卷时
   * @returns 返回一个Promise，完成时不返回值
   */
  async removeByPageId(pageId: string): Promise<void> {
    const survey: SurveyEntity[] = await this.surveyRepository.findBy({ pageId });

    if (isNil(survey)) {
      throw new BadRequestException(ErrorEnum.SURVEY_NOT_FOUND);
    }

    if (survey.length > 0) {
      await this.surveyRepository.remove(survey);
    } else {
      throw new BadRequestException(ErrorEnum.SURVEY_NOT_FOUND);
    }
  }

  /**
   * 根据租户ID查找最新的问卷和测试链接
   *
   * 该方法从数据库中获取指定租户ID下的所有有效问卷，
   * 按创建时间降序排序，并根据问卷类型(survey或quiz)返回最新的链接。
   *
   * @param tenantId - 租户ID
   * @returns 包含最新问卷和测试链接的对象
   * @throws {Error} 数据库查询失败时可能抛出异常
   */
  async findByTenantId(
    tenantId: number,
    diseaseId: number
  ): Promise<{ survey: string; quiz: string }> {
    this.logger.log(`开始查找问卷数据: tenantId=${tenantId}, diseaseId=${diseaseId}`);

    const surveys: SurveyEntity[] = await this.surveyRepository.find({
      where: {
        tenantId,
        pageId: Not(IsNull()) && Not(''), // 确保 pageId 有值 且 不为空字符串
      },
      order: {
        createdAt: 'DESC', // 按创建时间从最近到之前排序
      },
    });

    this.logger.log(`查询到问卷数据数量: ${surveys.length}`);

    // 根据类型分类
    const [survey, quiz] = [[], []];

    for (const item of surveys) {
      if (item.type === SurveyType.SURVEY) {
        survey.push(item);
      }

      if (item.type === SurveyType.QUIZ) {
        quiz.push(item);
      }
    }

    this.logger.log(`分类结果: survey数量=${survey.length}, quiz数量=${quiz.length}`);

    if (!diseaseId) {
      // 如果没有疾病分类ID，则返回最新的问卷和测试链接
      const result = {
        survey: survey[0]?.link ?? null,
        quiz: quiz[0]?.link ?? null,
      };
      this.logger.log(
        `未指定疾病分类ID，返回最新的问卷和测试链接，返回结果: ${JSON.stringify(result)}`
      );
      return result;
    }

    // 如果有疾病分类ID，则返回最新的问卷和测试链接
    const result = {
      survey: survey.find((item) => item.diseaseId === diseaseId)?.link ?? null,
      quiz: quiz.find((item) => item.diseaseId === diseaseId)?.link ?? null,
    };
    this.logger.log(
      `指定疾病分类ID=${diseaseId}，查找匹配的问卷和测试链接，返回结果: ${JSON.stringify(result)}`
    );
    return result;
  }

	/**
	 * 根据页面ID查找问卷
	 *
	 * @param pageId - 页面ID
	 * @returns 返回与指定页面ID关联的问卷实体
	 * @throws {BadRequestException} 当未提供页面ID时抛出异常
	 */
  async findByPageId(pageId: string): Promise<SurveyEntity> {
		this.logger.log(`查找问卷，页面ID: ${pageId}`);

    if (!pageId) {
      throw new BadRequestException(ErrorEnum.SURVEY_PAGE_ID_REQUIRED);
    }

    return await this.surveyRepository.findOneBy({ pageId });
  }
}
